home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Contributed / SpriteWorld / SpriteWorld Files / Utils / Brian's Extensions / BlitPixieRotated.c next >
Encoding:
C/C++ Source or Header  |  2000-10-06  |  34.1 KB  |  897 lines  |  [TEXT/CWIE]

  1. /*  -----------------------------------------------------------------------------------
  2.     -----------------------------------------------------------------------------------
  3.     BlitPixieRotated.c
  4.     
  5.     by Brian Roddy
  6.     
  7.     6/3/97
  8.  
  9.     converted to use fixpoint instead by afb 00-01-07
  10.     
  11.     
  12.     These are blitters for rendering rotated versions of a sprite. The routines work
  13.     in 8-bit, 16-bits, and 32-bit. The API is simple. Use SWSetSpriteRotation to set
  14.     the sprite's rotation. The amount of rotation must be between 0 to the constant
  15.     kNumberOfRotationSteps.  Calling SWSetSpriteRotation with 0 as the rotation will
  16.     reset the sprite to use the standard blitting routines.
  17.     
  18.     Example Use:
  19.     
  20.     SWSetSpriteRotation(mySpritePtr, 3);  // Rotate it
  21.         
  22.     SWSetSpriteRotation(mySpritePtr, 0);  // Reset it back to normal
  23.     
  24.     
  25.     Note that all rotation is clipped to frameRect of the sprite.  In other words, the sprite
  26.     is rotated within its bounding rectangle.  Thus if you have a long skinny sprite, part
  27.     of it will be lost while rotating it.  The fix to this problem is to make sure that you 
  28.     store the sprite in the resource with enough white space around it that it can rotate 
  29.     fully and have nothing lost.
  30.     
  31.     Also note that rotation is done on-the-fly.  As a result, it can 
  32.     be fairly slow and the pixels in the frames don't match what shows up on the screen.  
  33.     This means that functions which rely on the sprite's mask, such as SWPixelCollision, 
  34.     won't work as expected.  Thus using the pixel or mask collisions routines with 
  35.     rotated sprites won't work accurately.
  36.     
  37.     Because blitting rotated sprites is slow and there are collision issues, there is 
  38.     a function called CreateRotatedFrameFromFrame that can be called to create a new 
  39.     frame object which contains a rotated version of a frame. In this way the frame is 
  40.     precomputed and blits quickly.  Example Use:
  41.     
  42.     for (currentRotation = 1; currentRotation < 8; currentRotation++) 
  43.         CreateRotatedFrameFromFrame(gSpriteWorld, 
  44.                                     myFrames[0], 
  45.                                     &myFrames[currentRotation], 
  46.                                     currentRotation);
  47.     
  48.     Imagine an asteroids like game with a single ship image.  This would fill up a frame
  49.     array with rotated versions of the ship stored in frame zero. 
  50.     
  51.     One additional note.  We need the sin and cos function to do this rotation.  For speed
  52.     we precompute the values of sin and cos corresponding to each amount of rotation.
  53.     Since we often want to use 8, 16, 32, or 64 degrees of rotations, arrays of these
  54.     are predefined in our code.  
  55.     
  56.     If we wish to use a different number for kNumberOfRotationSteps, then we need to 
  57.     uncomment the #define DYNAMICALLY_GENERATE_TABLE in the header file for this code.
  58.     When DYNAMICALLY_GENERATE_TABLE is defined, we have to call InitializeRotationTables() 
  59.     to fill up the tables with values.  This requires including MathLib.  If this
  60.     sounds confusing, just leave kNumberOfRotationSteps with the value 8, 16, 32, or 64.
  61.     
  62.     -------------------------------------------------------------------------------------
  63.     Implementation Notes:
  64.  
  65.     A little about how this works.  The equations for rotation are:
  66.         x' = cos(rotation) * x + sin(rotation) * y
  67.         y' = cos(rotation) * y - sin(rotation) * x
  68.         
  69.     While rendering we precalculate as much of this equation as possible.  But we still
  70.     need to compute the corresponding source x and y for each pixel we blit.
  71.     
  72.     This was originally all done in floating point, but is now done in fixed point, 
  73.     making it much faster on 68k, and even a little faster on PPC too.
  74.  
  75.     This source code is available for free use.
  76.  
  77.     ----------------------------------------------------------------------------------- 
  78.     ----------------------------------------------------------------------------------- */
  79.  
  80. #ifndef __TOOLUTILS__
  81. #include <ToolUtils.h>
  82. #endif
  83.  
  84. #ifndef __OSUTILS__
  85. #include <OSUtils.h>
  86. #endif
  87.  
  88. #ifndef __QUICKDRAW__
  89. #include <Quickdraw.h>
  90. #endif
  91.  
  92. #ifndef __QDOFFSCREEN__
  93. #include <QDOffscreen.h>
  94. #endif
  95.  
  96. #ifndef __SWCOMMON__
  97. #include <SWCommonHeaders.h>
  98. #endif
  99.  
  100. #ifndef __SPRITEWORLDUTILS__
  101. #include <SpriteWorldUtils.h>
  102. #endif
  103.  
  104. #ifndef __SPRITEWORLD__
  105. #include <SpriteWorld.h>
  106. #endif
  107.  
  108. #include <BlitPixieRotated.h>
  109.  
  110.  
  111. // See section on sin/cosin caching below for more detail about this
  112. #ifdef DYNAMICALLY_GENERATE_TABLE
  113. #include <math.h>
  114. #endif
  115.  
  116. ///--------------------------------------------------------------------------------------
  117. ///--------------------------------------------------------------------------------------
  118. /// Public API:
  119. ///--------------------------------------------------------------------------------------
  120. ///--------------------------------------------------------------------------------------
  121.  
  122. #pragma mark ------------- Public API ---------------
  123.  
  124. SW_FUNC OSErr CreateRotatedFrameFromFrame(
  125.     SpriteWorldPtr     destSpriteWorld,
  126.     FramePtr         originalFrameP, 
  127.     FramePtr*         newFramePPtr, 
  128.     int             amountOfRotation) {
  129.     FramePtr newFrameP;
  130.     OSErr err;
  131.     
  132.     if (! ((destSpriteWorld->pixelDepth == 8) ||
  133.             (destSpriteWorld->pixelDepth == 16) ||
  134.             (destSpriteWorld->pixelDepth == 32))) {
  135.         // Only works in 8,16 or 32 bit modes
  136.         SWSetStickyIfError( kWrongDepthErr );
  137.         return kWrongDepthErr;
  138.     }
  139.  
  140.         // Copy the frame
  141.     SWCopyFrame(destSpriteWorld, originalFrameP, newFramePPtr, true);
  142.     newFrameP = *newFramePPtr;
  143.     
  144.         // Lock everything so we can rotate it
  145.     SWLockFrame(originalFrameP);
  146.     SWLockFrame(newFrameP);
  147.  
  148.         // Clear the old image by painting white, our mask color
  149.     SetGWorld(newFrameP->framePort, nil);
  150.     ForeColor(whiteColor);
  151.     PaintRect(&newFrameP->maskPort->portRect);
  152.     ForeColor(blackColor);    // Change back when done!
  153.     
  154.     
  155.         // Rotate the image, saving it in the new frame
  156.     if (destSpriteWorld->pixelDepth == 8) {
  157.         BlitPixieRotateFrame8Bit(originalFrameP, newFrameP,
  158.             &originalFrameP->frameRect, &newFrameP->frameRect, amountOfRotation);
  159.     } else if (destSpriteWorld->pixelDepth == 16) {
  160.         BlitPixieRotateFrame16Bit(originalFrameP, newFrameP,
  161.             &originalFrameP->frameRect, &newFrameP->frameRect, amountOfRotation);
  162.     } else /* if (destSpriteWorld->pixelDepth == 32) */ {
  163.         BlitPixieRotateFrame32Bit(originalFrameP, newFrameP,
  164.             &originalFrameP->frameRect, &newFrameP->frameRect, amountOfRotation);
  165.     }
  166.     
  167.         // Make a mask for the new rotated tile image
  168.     err = SWUpdateFrameMasks(newFrameP);
  169.  
  170.         // Return success
  171.     SWSetStickyIfError( err );
  172.     return err;
  173. }
  174.  
  175.  
  176. SW_FUNC OSErr SWSetSpriteRotation(
  177.     SpritePtr srcSpriteP,
  178.     unsigned char rotation) 
  179. {
  180.     short         currentPixelDepth;
  181.     OSErr        err;
  182.     
  183.     
  184.     currentPixelDepth = (*srcSpriteP->frameArray[0]->framePort->portPixMap)->pixelSize;
  185.     err = kWrongDepthErr;
  186.     
  187.     srcSpriteP->rotation = rotation;
  188.     
  189.     if (currentPixelDepth == 8)
  190.     {
  191.         if (rotation == 0)
  192.             srcSpriteP->frameDrawProc = BlitPixieMaskDrawProc;
  193.         else
  194.             srcSpriteP->frameDrawProc = BlitPixie8BitRotatedMaskDrawProc;
  195.         err = noErr;
  196.     }
  197.     else if (currentPixelDepth == 16)
  198.     {
  199.         if (rotation == 0)
  200.             srcSpriteP->frameDrawProc = BlitPixieMaskDrawProc;
  201.         else
  202.             srcSpriteP->frameDrawProc = BlitPixie16BitRotatedMaskDrawProc;
  203.         err = noErr;
  204.     }
  205.     else if (currentPixelDepth == 32)
  206.     {
  207.         if (rotation == 0)
  208.             srcSpriteP->frameDrawProc = BlitPixieMaskDrawProc;
  209.         else
  210.             srcSpriteP->frameDrawProc = BlitPixie32BitRotatedMaskDrawProc;
  211.         err = noErr;
  212.     }
  213.  
  214.     SWSetStickyIfError( err );
  215.     return err;
  216. }
  217.  
  218.  
  219. SW_FUNC unsigned char SWGetSpriteRotation(SpritePtr srcSpriteP) {
  220.     if ((srcSpriteP->frameDrawProc == BlitPixie8BitRotatedMaskDrawProc) ||
  221.         (srcSpriteP->frameDrawProc == BlitPixie16BitRotatedMaskDrawProc) ||
  222.         (srcSpriteP->frameDrawProc == BlitPixie32BitRotatedMaskDrawProc))
  223.         return srcSpriteP->rotation;
  224.     else 
  225.         return 0;
  226. }
  227.  
  228.  
  229. ///--------------------------------------------------------------------------------------
  230. ///--------------------------------------------------------------------------------------
  231. /// Internal Functions
  232. ///--------------------------------------------------------------------------------------
  233. ///--------------------------------------------------------------------------------------
  234.  
  235.  
  236. #pragma mark ---------- Sin/Cos Caching ------------
  237. ///--------------------------------------------------------------------------------------
  238. /// Sine/Cosine caching:
  239. ///--------------------------------------------------------------------------------------
  240. Boolean gRotationInitialized = false;
  241.  
  242. // if this is defined, we can use whatever value for kNumberOfRotationSteps that
  243. // we want.  We just have to call InitializeRotationTables to fill up the
  244. // tables with values...
  245. #ifdef DYNAMICALLY_GENERATE_TABLE
  246. double sineArray[kNumberOfRotationSteps];
  247. double cosineArray[kNumberOfRotationSteps];
  248.  
  249. void InitializeRotationTables(void) {
  250.     int i;
  251.     double curRotation;
  252.     for(i = 0; i < kNumberOfRotationSteps; i++) {
  253.         curRotation = ((double)i / (double)kNumberOfRotationSteps) * 2.0 * 3.1415926535;
  254.         sineArray[i] = sin(curRotation);
  255.         cosineArray[i] = cos(curRotation);
  256.     }
  257.     gRotationInitialized = true;
  258. }
  259. #else
  260. // ...Normally though we just want to use 8, 16, 32, or 64 rotations.  For these
  261. // we have precomputed them and automatically can put them in our array.  This means
  262. // we don't have to include any Math Library and it means we don't have to call 
  263. // InitializeRotationTables.
  264.  
  265. // The tables for 8 steps of rotation
  266. #if (kNumberOfRotationSteps == 8)
  267. double sineArray[8] = {0.0, 0.7071067811706742, 1.0, 0.7071067812341675, 8.979306187484326E-11, -0.707106781107181, -1.0, -0.7071067812976605};
  268. double cosineArray[8] = {1.0, 0.7071067812024209, 4.489653093742163E-11, -0.7071067811389276, -1.0, -0.7071067812659142, -1.346895928122649E-10, 0.7071067810754346};
  269. #endif
  270.  
  271. // The tables for 16 steps of rotation
  272. #if (kNumberOfRotationSteps == 16)
  273. double sineArray[16] = {0.0, 0.38268343235472, 0.7071067811706742, 0.9238795324984009, 1.0, 0.9238795325327632, 0.7071067812341675, 0.3826834324376778, 8.979306187484326E-11, -0.3826834322717618, -0.707106781107181, -0.9238795324640386, -1.0, -0.9238795325671256, -0.7071067812976605, -0.38268343252063575};
  274. double cosineArray[16] = {1.0, 0.9238795325155821, 0.7071067812024209, 0.382683432396199, 4.489653093742163E-11, -0.38268343231324103, -0.7071067811389276, -0.9238795324812198, -1.0, -0.9238795325499445, -0.7071067812659142, -0.38268343247915676, -1.346895928122649E-10, 0.38268343223028284, 0.7071067810754346, 0.9238795324468575};
  275. #endif
  276.  
  277. // The tables for 32 steps of rotation
  278. #if (kNumberOfRotationSteps == 32)
  279. double sineArray[32] = {0.0, 0.19509032201062404, 0.38268343235472, 0.5555702330056034, 0.7071067811706742, 0.8314696122869558, 0.9238795324984009, 0.9807852803955665, 1.0, 0.9807852804130842, 0.9238795325327632, 0.831469612336842, 0.7071067812341675, 0.5555702330802637, 0.3826834324376778, 0.19509032209869162, 8.979306187484326E-11, -0.1950903219225562, -0.3826834322717618, -0.5555702329309433, -0.707106781107181, -0.8314696122370696, -0.9238795324640386, -0.9807852803780487, -1.0, -0.980785280430602, -0.9238795325671256, -0.8314696123867287, -0.7071067812976605, -0.5555702331549235, -0.38268343252063575, -0.19509032218675934};
  280. double cosineArray[32] = {1.0, 0.9807852804043253, 0.9238795325155821, 0.831469612311899, 0.7071067812024209, 0.5555702330429335, 0.382683432396199, 0.1950903220546578, 4.489653093742163E-11, -0.19509032196659007, -0.38268343231324103, -0.5555702329682733, -0.7071067811389276, -0.8314696122620125, -0.9238795324812198, -0.9807852803868076, -1.0, -0.9807852804218431, -0.9238795325499445, -0.8314696123617852, -0.7071067812659142, -0.5555702331175935, -0.38268343247915676, -0.19509032214272548, -1.346895928122649E-10, 0.19509032187852235, 0.38268343223028284, 0.5555702328936128, 0.7071067810754346, 0.8314696122121265, 0.9238795324468575, 0.9807852803692898};
  281. #endif
  282.  
  283. // The tables for 64 steps of rotation
  284. #if (kNumberOfRotationSteps == 64)
  285. double sineArray[64] = {0.0, 0.09801714032676807, 0.19509032201062404, 0.2902846772464067, 0.38268343235472, 0.47139673681362415, 0.5555702330056034, 0.6343932841484619, 0.7071067811706742, 0.7730104533467158, 0.8314696122869558, 0.8819212643338048, 0.9238795324984009, 0.9569403357216197, 0.9807852803955665, 0.9951847266680713, 1.0, 0.9951847266768725, 0.9807852804130842, 0.9569403357476852, 0.9238795325327632, 0.8819212643761328, 0.831469612336842, 0.7730104534036799, 0.7071067812341675, 0.6343932842178729, 0.5555702330802637, 0.4713967368928147, 0.3826834324376778, 0.29028467733233315, 0.19509032209869162, 0.0980171404161287, 8.979306187484326E-11, -0.09801714023740733, -0.1950903219225562, -0.29028467716047995, -0.3826834322717618, -0.4713967367344339, -0.5555702329309433, -0.6343932840790509, -0.707106781107181, -0.7730104532897519, -0.8314696122370696, -0.8819212642914767, -0.9238795324640386, -0.9569403356955543, -0.9807852803780487, -0.99518472665927, -1.0, -0.9951847266856738, -0.980785280430602, -0.9569403357737509, -0.9238795325671256, -0.8819212644184612, -0.8314696123867287, -0.7730104534606443, -0.7071067812976605, -0.6343932842872835, -0.5555702331549235, -0.4713967369720047, -0.38268343252063575, -0.2902846774182598, -0.19509032218675934, -0.09801714050548939};
  286. double cosineArray[64] = {1.0, 0.9951847266724719, 0.9807852804043253, 0.9569403357346525, 0.9238795325155821, 0.8819212643549688, 0.831469612311899, 0.7730104533751978, 0.7071067812024209, 0.6343932841831673, 0.5555702330429335, 0.4713967368532193, 0.382683432396199, 0.2902846772893701, 0.1950903220546578, 0.09801714037144836, 4.489653093742163E-11, -0.09801714028208768, -0.19509032196659007, -0.2902846772034435, -0.38268343231324103, -0.4713967367740291, -0.5555702329682733, -0.6343932841137564, -0.7071067811389276, -0.7730104533182337, -0.8314696122620125, -0.8819212643126406, -0.9238795324812198, -0.956940335708587, -0.9807852803868076, -0.9951847266636706, -1.0, -0.9951847266812732, -0.9807852804218431, -0.9569403357607181, -0.9238795325499445, -0.8819212643972969, -0.8314696123617852, -0.7730104534321619, -0.7071067812659142, -0.634393284252578, -0.5555702331175935, -0.4713967369324095, -0.38268343247915676, -0.2902846773752965, -0.19509032214272548, -0.09801714046080905, -1.346895928122649E-10, 0.09801714019272699, 0.19509032187852235, 0.29028467711751665, 0.38268343223028284, 0.4713967366948383, 0.5555702328936128, 0.634393284044345, 0.7071067810754346, 0.7730104532612699, 0.8314696122121265, 0.8819212642703126, 0.9238795324468575, 0.9569403356825215, 0.9807852803692898, 0.9951847266548695};
  287. #endif
  288.  
  289. // In these cases, our Rotation Tables are already initialized so this function
  290. // does nothing.  We leave it here for consistency.
  291. void InitializeRotationTables(void) {}  
  292.  
  293. #endif
  294.  
  295.  
  296. ///--------------------------------------------------------------------------------------
  297. /// The Blitting Functions:
  298. ///--------------------------------------------------------------------------------------
  299.  
  300.  
  301. #pragma mark ------------ 8 Bit Blitters -------------
  302.  
  303. ///--------------------------------------------------------------------------------------
  304. //        BlitPixieRotateFrame8Bit
  305. ///--------------------------------------------------------------------------------------
  306. /// This version allows it to be called directly with a specified rotation.
  307. /// No need for any globals to be set.
  308.  
  309. SW_FUNC void BlitPixieRotateFrame8Bit(
  310.     FramePtr srcFrameP,
  311.     FramePtr dstFrameP,
  312.     Rect *srcRect,
  313.     Rect *dstRect,
  314.     short rotation)
  315. {
  316.     Rect dstBlitRect = *dstRect;
  317.     Rect srcBlitRect = *srcRect;
  318.     unsigned long         numBytesPerRow;
  319.     unsigned long         srcBaseOffset;
  320.     
  321.     SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
  322.     SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 8);
  323.     SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 8);
  324.     SW_ASSERT(srcFrameP->maskPort != NULL);
  325.  
  326.     BP_CLIP_RECT((&dstFrameP->frameRect), srcBlitRect, dstBlitRect);    
  327.     START_32_BIT_MODE
  328.  
  329.         // calculate the offset to the first byte of the source
  330.     srcBaseOffset = srcFrameP->scanLinePtrArray[srcBlitRect.top - srcFrameP->frameRect.top] + 
  331.         srcBlitRect.left;
  332.  
  333.         // calculate the number of bytes in a row
  334.     numBytesPerRow = (dstBlitRect.right - dstBlitRect.left);
  335.  
  336.     BlitPixieMask8BitRotated(
  337.             // calculate the address of the first byte of the source
  338.         (unsigned char *)(srcFrameP->frameBaseAddr + srcBaseOffset),
  339.  
  340.             // calculate the address of the first byte of the destination
  341.         (unsigned char *)(dstFrameP->frameBaseAddr + 
  342.             (dstFrameP->scanLinePtrArray[dstBlitRect.top]) + dstBlitRect.left),
  343.  
  344.             // calculate the address of the first byte of the mask
  345.         (unsigned char *)(srcFrameP->maskBaseAddr + srcBaseOffset),
  346.  
  347.             // calculate the number of rows to blit
  348.         dstBlitRect.bottom - dstBlitRect.top,
  349.  
  350.             // number of bytes in a row (duh!)
  351.         numBytesPerRow,
  352.  
  353.         srcFrameP->frameRowBytes,
  354.         dstFrameP->frameRowBytes,
  355.  
  356.         rotation
  357.         );
  358.  
  359.     END_32_BIT_MODE
  360. }
  361.  
  362.  
  363. /// This version of the drawproc is used by the system, and should be used as a sprite
  364. /// draw proc.  It requires that the global "gCurrentSpriteBeingDrawn" be set before being called.
  365. SW_FUNC void BlitPixie8BitRotatedMaskDrawProc(
  366.     FramePtr srcFrameP,
  367.     FramePtr dstFrameP,
  368.     Rect *srcRect,
  369.     Rect *dstRect)
  370. {
  371.     Rect dstBlitRect = *dstRect;
  372.     Rect srcBlitRect = *srcRect;
  373.     unsigned long         numBytesPerRow;
  374.     unsigned long         srcBaseOffset;
  375.     unsigned long         rotation = 0;
  376.     
  377.     SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
  378.     SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 8);
  379.     SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 8);
  380.     SW_ASSERT(srcFrameP->maskPort != NULL);
  381.     
  382.     if (gSWCurrentSpriteBeingDrawn != NULL)
  383.         rotation = gSWCurrentSpriteBeingDrawn->rotation;
  384.  
  385.     BP_CLIP_RECT((&dstFrameP->frameRect), srcBlitRect, dstBlitRect);    
  386.     START_32_BIT_MODE
  387.  
  388.         // calculate the offset to the first byte of the source
  389.     srcBaseOffset = srcFrameP->scanLinePtrArray[srcBlitRect.top - srcFrameP->frameRect.top] + 
  390.         srcBlitRect.left;
  391.  
  392.         // calculate the number of bytes in a row
  393.     numBytesPerRow = (dstBlitRect.right - dstBlitRect.left);
  394.  
  395.     BlitPixieMask8BitRotated(
  396.             // calculate the address of the first byte of the source
  397.         (unsigned char *)(srcFrameP->frameBaseAddr + srcBaseOffset),
  398.  
  399.             // calculate the address of the first byte of the destination
  400.         (unsigned char *)(dstFrameP->frameBaseAddr + 
  401.             (dstFrameP->scanLinePtrArray[dstBlitRect.top]) + dstBlitRect.left),
  402.  
  403.             // calculate the address of the first byte of the mask
  404.         (unsigned char *)(srcFrameP->maskBaseAddr + srcBaseOffset),
  405.  
  406.             // calculate the number of rows to blit
  407.         dstBlitRect.bottom - dstBlitRect.top,
  408.  
  409.             // number of bytes in a row (duh!)
  410.         numBytesPerRow,
  411.  
  412.         srcFrameP->frameRowBytes,
  413.         dstFrameP->frameRowBytes,
  414.  
  415.         rotation
  416.         );
  417.  
  418.     END_32_BIT_MODE
  419. }
  420.  
  421.  
  422. ///--------------------------------------------------------------------------------------
  423. //        BlitPixieMask8BitRotated
  424. ///--------------------------------------------------------------------------------------
  425. void BlitPixieMask8BitRotated(
  426.     register unsigned char *srcPixelP,
  427.     register unsigned char *dstPixelP,
  428.     register unsigned char *maskPixelP,
  429.     register unsigned long rowsToCopy,
  430.     register unsigned long numBytesPerRow,
  431.     register unsigned long srcOffset,
  432.     register unsigned long dstOffset,
  433.     register unsigned long curRotation)
  434. {
  435.     register unsigned char *rotatedPixelLocationP;
  436.     register unsigned char *rotatedMaskLocationP;
  437.     register int x, y, curOff;
  438.     int roundedNewX, roundedNewY;
  439.     unsigned long pixelWidth = numBytesPerRow;
  440.     register long cosineOfRotation = (cosineArray[curRotation] * 65536.0);
  441.     register long sineOfRotation = (sineArray[curRotation] * 65536.0);
  442.     long    midx,midy;
  443.     long    curX,curY;
  444.     long    xInc,yInc;
  445.     
  446.     // We pull all of these out to here so in our loop
  447.     // all we do is the minimal number of additions
  448.     midx = pixelWidth >> 1;
  449.     midy = rowsToCopy >> 1;    
  450.     curX = (midx << 16) - midx * cosineOfRotation - midy * sineOfRotation;
  451.     curY = (midy << 16) + midx * sineOfRotation - midy * cosineOfRotation;
  452.     xInc = sineOfRotation - (cosineOfRotation * pixelWidth);
  453.     yInc = cosineOfRotation + (sineOfRotation * pixelWidth);
  454.     
  455.     // Now we go through each pixel in the destination and compute the corresponding
  456.     // source pixel.  We could do this in reverse (go through source, and compute the
  457.     // destination) and it would be faster, but round off error leaves holes in the
  458.     // image.  This is the correct way.
  459.     for (y = 0; y < rowsToCopy; y++) {
  460.         for (x = 0; x < numBytesPerRow; x++) {
  461.             curX += cosineOfRotation;
  462.             curY -= sineOfRotation;
  463.         
  464.             // round it to an integer for the array lookup
  465.             roundedNewX = curX >> 16;
  466.             roundedNewY = curY >> 16;
  467.             
  468.             // Super safe bounds checking (for now)
  469.             // We only rotate inside our bounds
  470.             // we could potentially speed this up to figure out where to start
  471.             if ((roundedNewX >= 0) && (roundedNewY >= 0) && 
  472.                 (roundedNewX < numBytesPerRow) && (roundedNewY < rowsToCopy)) {
  473.                 // Compute the memory location corresponding to the new x and y.
  474.                 // potential place to speed it up is here
  475.                 curOff = roundedNewX + (srcOffset * roundedNewY);
  476.                 rotatedMaskLocationP = maskPixelP + curOff;
  477.                 if (*rotatedMaskLocationP == 0) {
  478.                     rotatedPixelLocationP = srcPixelP + curOff;
  479.                     dstPixelP[x] = *rotatedPixelLocationP;
  480.                 }
  481.             }
  482.         }
  483.         // bump down one row and reset x back to 0
  484.         curX += xInc;
  485.         curY += yInc;
  486.                 
  487.         // Go to next row.
  488.         dstPixelP += dstOffset;
  489.     }
  490. }
  491.  
  492. #pragma mark ----------- 16 Bit Blitters -------------
  493. ///--------------------------------------------------------------------------------------
  494. //        BlitPixieRotateFrame16Bit
  495. ///--------------------------------------------------------------------------------------
  496. /// This version allows it to be called directly with a specified rotation.
  497. /// No need for any globals to be set.
  498.  
  499. SW_FUNC void BlitPixieRotateFrame16Bit(
  500.     FramePtr srcFrameP,
  501.     FramePtr dstFrameP,
  502.     Rect *srcRect,
  503.     Rect *dstRect,
  504.     short rotation)
  505. {
  506.     Rect dstBlitRect = *dstRect;
  507.     Rect srcBlitRect = *srcRect;
  508.     unsigned long         numBytesPerRow;
  509.     unsigned long         srcBaseOffset;
  510.     
  511.     SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
  512.     SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 16);
  513.     SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 16);
  514.     SW_ASSERT(srcFrameP->maskPort != NULL);
  515.     
  516.     BP_CLIP_RECT((&dstFrameP->frameRect), srcBlitRect, dstBlitRect);    
  517.     START_32_BIT_MODE
  518.  
  519.         // calculate the offset to the first byte of the source
  520.     srcBaseOffset = srcFrameP->scanLinePtrArray[srcBlitRect.top - srcFrameP->frameRect.top] + 
  521.         srcBlitRect.left;
  522.  
  523.         // calculate the number of bytes in a row
  524.     numBytesPerRow = (dstBlitRect.right - dstBlitRect.left) << 1;
  525.  
  526.     BlitPixieMask16BitRotated(
  527.             // calculate the address of the first byte of the source
  528.         (unsigned short *)(srcFrameP->frameBaseAddr + srcBaseOffset),
  529.  
  530.             // calculate the address of the first byte of the destination
  531.         (unsigned short *)(dstFrameP->frameBaseAddr + 
  532.             (dstFrameP->scanLinePtrArray[dstBlitRect.top]) + 
  533.             (dstBlitRect.left << 1)),
  534.  
  535.             // calculate the address of the first byte of the mask
  536.         (unsigned short *)(srcFrameP->maskBaseAddr + srcBaseOffset),
  537.  
  538.             // calculate the number of rows to blit
  539.         dstBlitRect.bottom - dstBlitRect.top,
  540.  
  541.             // number of bytes in a row (duh!)
  542.         numBytesPerRow,
  543.  
  544.         srcFrameP->frameRowBytes,
  545.         dstFrameP->frameRowBytes,
  546.  
  547.         rotation
  548.         );
  549.         
  550.     END_32_BIT_MODE
  551. }
  552.  
  553.  
  554. ///--------------------------------------------------------------------------------------
  555. //        BlitPixie16BitRotatedMaskDrawProc
  556. ///--------------------------------------------------------------------------------------
  557. /// This version of the drawproc is used by the system, and should be used as a sprite
  558. /// draw proc.  It requires that the global "gCurrentSpriteBeingDrawn" be set before being called.
  559.  
  560. SW_FUNC void BlitPixie16BitRotatedMaskDrawProc(
  561.     FramePtr srcFrameP,
  562.     FramePtr dstFrameP,
  563.     Rect *srcRect,
  564.     Rect *dstRect)
  565. {
  566.     Rect dstBlitRect = *dstRect;
  567.     Rect srcBlitRect = *srcRect;
  568.     unsigned long         numBytesPerRow;
  569.     unsigned long         srcBaseOffset;
  570.     unsigned long         rotation = 0;
  571.  
  572.     SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
  573.     SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 16);
  574.     SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 16);
  575.     SW_ASSERT(srcFrameP->maskPort != NULL);
  576.     
  577.     if (gSWCurrentSpriteBeingDrawn != NULL)
  578.         rotation = gSWCurrentSpriteBeingDrawn->rotation;
  579.  
  580.     BP_CLIP_RECT((&dstFrameP->frameRect), srcBlitRect, dstBlitRect);    
  581.     START_32_BIT_MODE
  582.  
  583.         // calculate the offset to the first byte of the source
  584.     srcBaseOffset = srcFrameP->scanLinePtrArray[srcBlitRect.top - srcFrameP->frameRect.top] + 
  585.         srcBlitRect.left;
  586.  
  587.         // calculate the number of bytes in a row
  588.     numBytesPerRow = (dstBlitRect.right - dstBlitRect.left) << 1;
  589.  
  590.     BlitPixieMask16BitRotated(
  591.             // calculate the address of the first byte of the source
  592.         (unsigned short *)(srcFrameP->frameBaseAddr + srcBaseOffset),
  593.  
  594.             // calculate the address of the first byte of the destination
  595.         (unsigned short *)(dstFrameP->frameBaseAddr + 
  596.             (dstFrameP->scanLinePtrArray[dstBlitRect.top]) + 
  597.             (dstBlitRect.left << 1)),
  598.  
  599.             // calculate the address of the first byte of the mask
  600.         (unsigned short *)(srcFrameP->maskBaseAddr + srcBaseOffset),
  601.  
  602.             // calculate the number of rows to blit
  603.         dstBlitRect.bottom - dstBlitRect.top,
  604.  
  605.             // number of bytes in a row (duh!)
  606.         numBytesPerRow,
  607.  
  608.         srcFrameP->frameRowBytes,
  609.         dstFrameP->frameRowBytes,
  610.  
  611.         rotation
  612.         );
  613.  
  614.     END_32_BIT_MODE
  615. }
  616.  
  617.  
  618. ///--------------------------------------------------------------------------------------
  619. //        BlitPixieMask16BitRotated
  620. ///--------------------------------------------------------------------------------------
  621. void BlitPixieMask16BitRotated(
  622.     register unsigned short *srcPixelP,
  623.     register unsigned short *dstPixelP,
  624.     register unsigned short *maskPixelP,
  625.     register unsigned long rowsToCopy,
  626.     register unsigned long numBytesPerRow,
  627.     register unsigned long srcOffset,
  628.     register unsigned long dstOffset,
  629.     register unsigned long curRotation)
  630. {
  631.     register unsigned short *rotatedPixelLocationP;
  632.     register unsigned short *rotatedMaskLocationP;
  633.     register int x, y, curOff;
  634.     register int roundedNewX, roundedNewY;
  635.     
  636.     // We pull all of these out to here so in our loop
  637.     // all we do is the minimal number of additions
  638.     register unsigned long pixelWidth = numBytesPerRow / 2;
  639.     register long cosineOfRotation = (cosineArray[curRotation] * 65536.0);
  640.     register long sineOfRotation = (sineArray[curRotation] * 65536.0);
  641.     long    midx,midy;
  642.     long    curX,curY;
  643.     long    xInc,yInc;
  644.     
  645.     // We pull all of these out to here so in our loop
  646.     // all we do is the minimal number of additions
  647.     midx = pixelWidth >> 1;
  648.     midy = rowsToCopy >> 1;    
  649.     curX = (midx << 16) - midx * cosineOfRotation - midy * sineOfRotation;
  650.     curY = (midy << 16) + midx * sineOfRotation - midy * cosineOfRotation;
  651.     xInc = sineOfRotation - (cosineOfRotation * pixelWidth);
  652.     yInc = cosineOfRotation + (sineOfRotation * pixelWidth);
  653.  
  654.     // divide the offsets by 2 to get number of shorts from bytes
  655.     srcOffset >>= 1;
  656.     dstOffset >>= 1;
  657.     
  658.     // Now we go through each pixel in the destination and compute the corresponding
  659.     // source pixel.  We could do this in reverse (go through source, and compute the
  660.     // destination) and it would be faster, but round off error leaves holes in the
  661.     // image.  This is the correct way.
  662.     for (y = 0; y < rowsToCopy; y++) {
  663.         for (x = 0; x < pixelWidth; x++) {
  664.             curX += cosineOfRotation;
  665.             curY -= sineOfRotation;
  666.         
  667.             // round it to an integer for the array lookup
  668.             roundedNewX = curX >> 16;
  669.             roundedNewY = curY >> 16;
  670.             
  671.             // Super safe bounds checking (for now)
  672.             // We only rotate inside our bounds
  673.             // we could potentially speed this up to figure out where to start
  674.             if ((roundedNewX >= 0) && (roundedNewY >= 0) && 
  675.                 (roundedNewX < pixelWidth) && (roundedNewY < rowsToCopy)) {
  676.                 // Compute the memory location corresponding to the new x and y.
  677.                 // potential place to speed it up is here
  678.                 curOff = roundedNewX + (srcOffset * roundedNewY);
  679.                 rotatedMaskLocationP = maskPixelP + curOff;
  680.                 if (*rotatedMaskLocationP == 0) {
  681.                     rotatedPixelLocationP = srcPixelP + curOff;
  682.                     dstPixelP[x] = *rotatedPixelLocationP;
  683.                 }
  684.             }
  685.         }
  686.         // bump down one row and reset x back to 0
  687.         curX += xInc;
  688.         curY += yInc;
  689.  
  690.         // Go to next row.
  691.         dstPixelP += dstOffset;
  692.     }
  693. }
  694.  
  695. #pragma mark ---------- 32 Bit Blitters -------------
  696. ///--------------------------------------------------------------------------------------
  697. //        BlitPixieRotateFrame32Bit
  698. ///--------------------------------------------------------------------------------------
  699. /// This version allows it to be called directly with a specified rotation.
  700. /// No need for any globals to be set.
  701.  
  702. SW_FUNC void BlitPixieRotateFrame32Bit(
  703.     FramePtr srcFrameP,
  704.     FramePtr dstFrameP,
  705.     Rect *srcRect,
  706.     Rect *dstRect,
  707.     short rotation)
  708. {
  709.     Rect dstBlitRect = *dstRect;
  710.     Rect srcBlitRect = *srcRect;
  711.     unsigned long         numBytesPerRow;
  712.     unsigned long         srcBaseOffset;
  713.     
  714.     SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
  715.     SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 32);
  716.     SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 32);
  717.     SW_ASSERT(srcFrameP->maskPort != NULL);
  718.     
  719.     BP_CLIP_RECT((&dstFrameP->frameRect), srcBlitRect, dstBlitRect);    
  720.     START_32_BIT_MODE
  721.  
  722.         // calculate the offset to the first byte of the source
  723.     srcBaseOffset = srcFrameP->scanLinePtrArray[srcBlitRect.top - srcFrameP->frameRect.top] + 
  724.         srcBlitRect.left;
  725.  
  726.         // calculate the number of bytes in a row
  727.     numBytesPerRow = (dstBlitRect.right - dstBlitRect.left) << 2;
  728.  
  729.     BlitPixieMask32BitRotated(
  730.             // calculate the address of the first byte of the source
  731.         (unsigned long *)(srcFrameP->frameBaseAddr + srcBaseOffset),
  732.  
  733.             // calculate the address of the first byte of the destination
  734.         (unsigned long *)(dstFrameP->frameBaseAddr + 
  735.             (dstFrameP->scanLinePtrArray[dstBlitRect.top]) + 
  736.             (dstBlitRect.left << 2)),
  737.  
  738.             // calculate the address of the first byte of the mask
  739.         (unsigned long *)(srcFrameP->maskBaseAddr + srcBaseOffset),
  740.  
  741.             // calculate the number of rows to blit
  742.         dstBlitRect.bottom - dstBlitRect.top,
  743.  
  744.             // number of bytes in a row (duh!)
  745.         numBytesPerRow,
  746.  
  747.         srcFrameP->frameRowBytes,
  748.         dstFrameP->frameRowBytes,
  749.  
  750.         rotation
  751.         );
  752.         
  753.     END_32_BIT_MODE
  754. }
  755.  
  756.  
  757. ///--------------------------------------------------------------------------------------
  758. //        BlitPixie32BitRotatedMaskDrawProc
  759. ///--------------------------------------------------------------------------------------
  760. /// This version of the drawproc is used by the system, and should be used as a sprite
  761. /// draw proc.  It requires that the global "gCurrentSpriteBeingDrawn" be set before being called.
  762.  
  763. SW_FUNC void BlitPixie32BitRotatedMaskDrawProc(
  764.     FramePtr srcFrameP,
  765.     FramePtr dstFrameP,
  766.     Rect *srcRect,
  767.     Rect *dstRect)
  768. {
  769.     Rect dstBlitRect = *dstRect;
  770.     Rect srcBlitRect = *srcRect;
  771.     unsigned long         numBytesPerRow;
  772.     unsigned long         srcBaseOffset;
  773.     unsigned long         rotation = 0;
  774.  
  775.     SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
  776.     SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 32);
  777.     SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 32);
  778.     SW_ASSERT(srcFrameP->maskPort != NULL);
  779.     
  780.     if (gSWCurrentSpriteBeingDrawn != NULL)
  781.         rotation = gSWCurrentSpriteBeingDrawn->rotation;
  782.  
  783.     BP_CLIP_RECT((&dstFrameP->frameRect), srcBlitRect, dstBlitRect);    
  784.     START_32_BIT_MODE
  785.  
  786.         // calculate the offset to the first byte of the source
  787.     srcBaseOffset = srcFrameP->scanLinePtrArray[srcBlitRect.top - srcFrameP->frameRect.top] + 
  788.         srcBlitRect.left;
  789.  
  790.         // calculate the number of bytes in a row
  791.     numBytesPerRow = (dstBlitRect.right - dstBlitRect.left) << 2;
  792.  
  793.     BlitPixieMask32BitRotated(
  794.             // calculate the address of the first byte of the source
  795.         (unsigned long *)(srcFrameP->frameBaseAddr + srcBaseOffset),
  796.  
  797.             // calculate the address of the first byte of the destination
  798.         (unsigned long *)(dstFrameP->frameBaseAddr + 
  799.             (dstFrameP->scanLinePtrArray[dstBlitRect.top]) + 
  800.             (dstBlitRect.left << 2)),
  801.  
  802.             // calculate the address of the first byte of the mask
  803.         (unsigned long *)(srcFrameP->maskBaseAddr + srcBaseOffset),
  804.  
  805.             // calculate the number of rows to blit
  806.         dstBlitRect.bottom - dstBlitRect.top,
  807.  
  808.             // number of bytes in a row (duh!)
  809.         numBytesPerRow,
  810.  
  811.         srcFrameP->frameRowBytes,
  812.         dstFrameP->frameRowBytes,
  813.  
  814.         rotation
  815.         );
  816.  
  817.     END_32_BIT_MODE
  818. }
  819.  
  820.  
  821. ///--------------------------------------------------------------------------------------
  822. //        BlitPixieMask32BitRotated
  823. ///--------------------------------------------------------------------------------------
  824. void BlitPixieMask32BitRotated(
  825.     register unsigned long *srcPixelP,
  826.     register unsigned long *dstPixelP,
  827.     register unsigned long *maskPixelP,
  828.     register unsigned long rowsToCopy,
  829.     register unsigned long numBytesPerRow,
  830.     register unsigned long srcOffset,
  831.     register unsigned long dstOffset,
  832.     register unsigned long curRotation)
  833. {
  834.     register unsigned long *rotatedPixelLocationP;
  835.     register unsigned long *rotatedMaskLocationP;
  836.     register int x, y, curOff;
  837.     register int roundedNewX, roundedNewY;
  838.     unsigned long pixelWidth = numBytesPerRow / 4;
  839.     register long cosineOfRotation = (cosineArray[curRotation] * 65536.0);
  840.     register long sineOfRotation = (sineArray[curRotation] * 65536.0);
  841.     long    midx,midy;
  842.     long    curX,curY;
  843.     long    xInc,yInc;
  844.     
  845.     // We pull all of these out to here so in our loop
  846.     // all we do is the minimal number of additions
  847.     midx = pixelWidth >> 1;
  848.     midy = rowsToCopy >> 1;    
  849.     curX = (midx << 16) - midx * cosineOfRotation - midy * sineOfRotation;
  850.     curY = (midy << 16) + midx * sineOfRotation - midy * cosineOfRotation;
  851.     xInc = sineOfRotation - (cosineOfRotation * pixelWidth);
  852.     yInc = cosineOfRotation + (sineOfRotation * pixelWidth);
  853.  
  854.     // divide the offsets by 4 to get number of longs from bytes
  855.     srcOffset >>= 2;
  856.     dstOffset >>= 2;
  857.     
  858.     // Now we go through each pixel in the destination and compute the corresponding
  859.     // source pixel.  We could do this in reverse (go through source, and compute the
  860.     // destination) and it would be faster, but round off error leaves holes in the
  861.     // image.  This is the correct way.
  862.     for (y = 0; y < rowsToCopy; y++) {
  863.         for (x = 0; x < pixelWidth; x++) {
  864.             curX += cosineOfRotation;
  865.             curY -= sineOfRotation;
  866.         
  867.             // round it to an integer for the array lookup
  868.             roundedNewX = curX >> 16;
  869.             roundedNewY = curY >> 16;
  870.             
  871.             // Super safe bounds checking (for now)
  872.             // We only rotate inside our bounds
  873.             // we could potentially speed this up to figure out where to start
  874.             if ((roundedNewX >= 0) && (roundedNewY >= 0) && 
  875.                 (roundedNewX < pixelWidth) && (roundedNewY < rowsToCopy))
  876.             {
  877.                 // Compute the memory location corresponding to the new x and y.
  878.                 // potential place to speed it up is here
  879.                 curOff = roundedNewX + (srcOffset * roundedNewY);
  880.                 rotatedMaskLocationP = maskPixelP + curOff;
  881.                 if (*rotatedMaskLocationP == 0)
  882.                 {
  883.                     rotatedPixelLocationP = srcPixelP + curOff;
  884.                     dstPixelP[x] = *rotatedPixelLocationP;
  885.                 }
  886.             }
  887.         }
  888.         // bump down one row and reset x back to 0
  889.         curX += xInc;
  890.         curY += yInc;
  891.  
  892.         // Go to next row.
  893.         dstPixelP += dstOffset;
  894.     }
  895. }
  896.  
  897.